/*********************\
 * file:     Main
 * version:  0.1a
 * package:  lwjgltest
 * 
 * author:   linus
 * team:     NexT
 * license:  -
\*********************/

package JnRTest;
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.lwjgl.LWJGLException;
import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display;

public class Main {
  public static int d_height = 480;
  public static int d_width = 640;
  public static final Logger LOGGER = Logger.getLogger(Main.class.getName());

  public int squareSize;
  public int squareX;
  public int squareY;
  public int squareZ;
  public int viewX=100;
  public int viewY=100;
  public double vsp;
  public double hsp;
  public double hcc=0.2,dcc=0.1,vcc=7,grav=0.2,hmax=10,vmax=10;
  public boolean ground=false,c_left=false,c_right=false,c_top=false,c_water=false;
  public ArrayList<Rectangle> rects;
  public ArrayList<Water> waters;
  boolean k_space,k_left,k_right;
  static {
    try {LOGGER.addHandler(new FileHandler("errors.log",true));
    }catch(IOException ex){LOGGER.log(Level.WARNING,ex.toString(),ex);}
  }

  public static void main(String[] args) {
    Main main = null;
    try {
      main = new Main();
      main.create();
      main.run();
    }
    catch(Exception ex) {LOGGER.log(Level.SEVERE,ex.toString(),ex);}
    finally {if(main != null)main.destroy();}
  }

  public Main() {
    rects = new ArrayList();
    waters= new ArrayList();
    squareSize = 50;
    squareX = 600;
    squareY = 700;
    squareZ = 0;
    vsp=0;
    hsp=0;
  }

  public void create() throws LWJGLException {
    //Display;
    Display.setFullscreen(true);
    Display.setTitle("LWJGL TEST");
    Display.create();
    d_width = Display.getDisplayMode().getWidth();
    d_height = Display.getDisplayMode().getHeight();

    //add blocks
    int dd=500;
    rects.add(new Rectangle(dd,     dd,      2000,      25));
    rects.add(new Rectangle(dd,     dd+25,   200,       100));
    waters.add(new Water   (dd+200, dd+25,   200,       75));
    rects.add(new Rectangle(dd+300, dd+25,   50,        25));
    rects.add(new Rectangle(dd+350, dd+25,   50,        50));
    rects.add(new Rectangle(dd+400, dd+25,   200,       100));
    rects.add(new Rectangle(dd+650, dd+175,  200,       50));

    //INPUT
    Keyboard.create();
    Mouse.setGrabbed(false);
    Mouse.create();

    initGL();
    resizeGL();
  }

  public void destroy() {
    //Methods already check if created before destroying.
    Mouse.destroy();
    Keyboard.destroy();
    Display.destroy();
  }

  public void initGL() {
    //2D Initialization
    glClearColor(0.0f,0.0f,0.0f,0.0f);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_LIGHTING);
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  }

  public void processKeyboard(){
    k_space=Keyboard.isKeyDown(Keyboard.KEY_SPACE);
    k_left =Keyboard.isKeyDown(Keyboard.KEY_LEFT);
    k_right=Keyboard.isKeyDown(Keyboard.KEY_RIGHT);
  }

  public void processMouse() {
    //squareX = Mouse.getX();
    //squareY = Mouse.getY();
  }

  public void render() {
    glClear(GL_COLOR_BUFFER_BIT);

    glPushMatrix();
    glTranslatef(-viewX,-viewY,0.0f);

    glPolygonMode ( GL_FRONT_AND_BACK, GL_LINE ); //Wireframe mode

    for(int i=0;i<rects.size();i++){
        rects.get(i).draw(true);
    }

    glPushMatrix();
    glTranslatef(squareX,squareY,0.0f);
    glColor3f(0.3f,0.3f,1.0f);
    glBegin(GL_QUADS);
      glVertex2f(0.0f,0.0f);
      glVertex2f(squareSize,0.0f);
      glVertex2f(squareSize,squareSize);
      glVertex2f(0.0f,squareSize);
    glEnd();
    glPopMatrix();

    glPolygonMode ( GL_FRONT_AND_BACK, GL_FILL );

    for(int i=0;i<rects.size();i++){
        rects.get(i).draw(false);
    }for(int i=0;i<waters.size();i++){
        waters.get(i).rect.draw(false);
    }


    glPopMatrix();

  }

  public void resizeGL() {
    //2D Scene
    glViewport(0,0,d_width,d_height);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0f,d_width,0.0f,d_height);
    glPushMatrix();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glPushMatrix();
  }

  public void run() {
    while(!Display.isCloseRequested() && !Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
      if(Display.isVisible()) {
        processKeyboard();
        processMouse();
        update();
        render();
      }
      else {
        if(Display.isDirty())render();
        try {Thread.sleep(100);}
        catch(InterruptedException ex) {}
      }
        Display.update();
        Display.sync(60);
    }
  }

  public void update() {

    //collisions
    ground=false;c_left=false;c_right=false;c_top=false;c_water=false;
    for(int i=0;i<rects.size();i++){
        if(ground!=true)ground = collisionLine(squareX+hsp+1,squareY+vsp,squareX+hsp+49,squareY+vsp,rects.get(i));
        if(c_left!=true)c_left = collisionLine(squareX+hsp,squareY+1,squareX+hsp,squareY+49,rects.get(i));
        if(c_right!=true)c_right=collisionLine(squareX+50+hsp,squareY+1,squareX+50+hsp,squareY+49,rects.get(i));
        if(c_top!=true)c_top   = collisionLine(squareX+hsp+1,squareY+50+vsp,squareX+hsp+49,squareY+50+vsp,rects.get(i));

    }for(int i=0;i<waters.size();i++){
        if(c_water!=true)c_water = collisionPoint(squareX+25,squareY+25,waters.get(i).rect);
    }

    //gravity
    if(!ground)vsp-=grav;else vsp=0;

    //movement
    if(k_space&&ground)vsp+=vcc;
    if(k_left)hsp-=hcc;
    if(k_right)hsp+=hcc;

    //limiters
    if(hsp<-hmax)hsp=-hmax;
    if(hsp> hmax)hsp= hmax;
    if(vsp<-vmax)vsp=-vmax;
    if(vsp> vmax)vsp= vmax;
    if(c_left&&hsp<0)hsp=0;
    if(c_right&&hsp>0)hsp=0;
    if(c_top&&vsp>0)vsp=0;

    //friction
    if(!k_left&&!k_right){
        if(hsp> 0.05)hsp-=dcc;
        if(hsp<-0.05)hsp+=dcc;
    }
    if(hsp>-0.05&&hsp<0.05)hsp=0;

    //water friction
    if(c_water){
        hsp-=hsp/20;
        vsp-=vsp/20;
    }

    //update
    squareX+=hsp;
    squareY+=vsp;


    //view update
    if(squareX>viewX+d_width-300)viewX=squareX-d_width+300;
    if(squareY>viewY+d_height-300)viewY=squareY-d_height+300;
    if(squareX<viewX+300)        viewX=squareX-300;
    if(squareY<viewY+300)        viewY=squareY-300;
  }

  public boolean collisionPoint(double x,double y,Rectangle rec){
      if(x>(rec.x+rec.w))return false;
      if(y>(rec.y+rec.h))return false;
      if(x<rec.x)return false;
      if(y<rec.y)return false;
      return true;
  }

  public boolean collisionLine(double ax,double ay,double bx,double by,Rectangle rec){
      boolean b=false;
      if(collisionPoint(ax,ay,rec)||collisionPoint(bx,by,rec))return true;
      double len = Math.sqrt((ax-bx)*(ax-bx)+(ay-by)*(ay-by));
      
      //TODO: NexT.geom.Line implementation
      /*for(int i=1;i<len-2;i+=len/5){
        
      }*/
      return b;
  }
}
